This vignette outlines the steps of inference, analysis and visualization of cell-cell communication at single-cell resolution for a single spatial transcriptomics dataset using Spatial CellChat. We showcase Spatial CellChat’s application to spatial transcriptomics data by applying it to a 10X Visium data on cells from human psoriatic skin (https://www.nature.com/articles/s41467-023-39020-4). Biological annotations of spots (i.e., cell group information) are obtained from the original study.
Spatial CellChat requires gene expression and spatial location data of spots/cells as the user input and models the probability of cell-cell communication by integrating gene expression with spatial distance as well as prior knowledge of the interactions between signaling ligands, receptors and their cofactors.
Upon infering the intercellular communication network, Spatial CellChat’s various functionality can be used for further data exploration, analysis, and visualization.
library(SpatialCellChat)
library(Matrix)
library(patchwork)
options(stringsAsFactors = F)
# use `SetEnvironment` to do parallel computation and get Python back-end
setEnvironment(workers = 2,future.globals.maxSize = 100000*1024^2, conda_env = NULL)
#> ℹ Future strategy in use: `parallel with 2 workers`
# setEnvironment(2,future.globals.maxSize = 100000*1024^2,conda_env = "/home/xzcheng/miniconda3/envs/Chat")
When inferring spatially resolved cell-cell communication from spatial transcriptomic data, user also should provide spatial coordinates/locations of spot/cell centroids. In addition, to filter out cell-cell communication beyond the maximum diffusion range of molecules (e.g., ~250μm), Spatial CellChat needs to compute the cell centroid-to-centroid distance in the unit of micrometers. Therefore, for spatial technologies that only provide spatial coordinates in pixels, CellChat converts spatial coordinates from pixels to micrometers by requiring users to input the conversion factor.
Spatial CellChat requires four user inputs:
data.input (Gene expression data of
spots/cells): genes should be in rows with rownames and cells
in columns with colnames. Normalized data (e.g., library-size
normalization and then log-transformed with a pseudocount of 1) is
required as input for Spatial CellChat analysis. If user provides count
data, we provide a normalizeData function to account for
library size and then do log-transformed.
meta (User assigned cell labels and samples
labels): a data frame (rows are cells with rownames) consisting
of cell information, which will be used for defining cell groups. When
performing spatial transcriptomics analysis with multiple
samples/replicates, a column named samples should be
provided. Of note, for comparison analysis across different conditions,
users still need to create a CellChat object seperately for each
condition.
coordinates (Spatial coordinates of
spots/cells): a data frame in which each row gives the spatial
coordinates/locations of each cell/spot centroid.
spatial.factors (Spatial factors of spatial
distance): a data frame containing two distance factors
ratio and tol, which is dependent on spatial
transcriptomics technologies (and specific datasets). (i)
ratio: the conversion factor when converting spatial
coordinates from Pixels or other units to Micrometers (i.e.,Microns).
For example, setting ratio = 0.18 indicates that 1 pixel
equals 0.18um in the coordinates. (ii) tol: the tolerance
factor to increase the robustness when comparing the center-to-center
distance against the interaction.range. This can be the
half value of cell/spot size in the unit of um. Please check the
vignette
of FAQ on applying CellChat to spatially resolved transcriptomics
data for detailed explanations and setting of different technologies
of spatial transcriptomics data.
When inferring contact-dependent or juxtacrine signaling by setting
contact.dependent = TRUE in computeCommunProb,
and using L-R pairs from Cell-Cell Contact signaling
classified in CellChatDB$interaction$annotation, CellChat
requires another one user input:
contact.range: a value giving the
interaction range (Unit: microns) to restrict the contact-dependent
signaling. For spatial transcriptomics in a single-cell resolution,
contact.range is approximately equal to the estimated cell
diameter (i.e., the cell center-to-center distance), which means that
contact-dependent or juxtacrine signaling can only happens when the two
cells are contact to each other. Typically,
contact.range = 10, which is a typical human cell
size.# Here we load a Seurat object of 10X Visium human psoriatic skin data and its associated cell meta data
# load("/Users/suoqinjin/Library/CloudStorage/OneDrive-Personal/works/SpatialCellChat/tutorial/visium_human_psoriasis.RData")
load("./tutorial/visium_human_psoriasis.RData")
Seurat::DefaultAssay(seu) <- "Spatial"
seu@assays$Spatial@counts <- seu@assays$Spatial@data
seu <- Seurat::NormalizeData(seu)
## Prepare input data for Spatial CelChat analysis
# get the deconvoluted cell type decomposition for this 10X Visium data
cell.type.decomposition <- t(seu@assays[["predictions"]]@data)
cell.type.decomposition[cell.type.decomposition<0.1] <- 0
which(round(rowSums(cell.type.decomposition))!=1.)
#> named integer(0)
# prepare spatial transcriptomics information
spatial.locs <- Seurat::GetTissueCoordinates(seu, scale = NULL, cols = c("imagerow", "imagecol"))
# adjust the view
spatial.locs[,2] <- max(spatial.locs[,2])-spatial.locs[,2]
temp_coordinates <- spatial.locs
spatial.locs[,1] <- temp_coordinates[,2]
spatial.locs[,2] <- temp_coordinates[,1]
spatial.locs[,1] <- max(spatial.locs[,1])-spatial.locs[,1]
colnames(spatial.locs) <- c("x", "y")
# spatial factors of spatial coordinates
# For 10X Visium, the conversion factor of converting spatial coordinates from Pixels to Micrometers can be computed as the ratio of the theoretical spot size (i.e., 65um) over the number of pixels that span the diameter of a theoretical spot size in the full-resolution image (i.e., 'spot_diameter_fullres' in pixels in the 'scalefactors_json.json' file).
# Of note, the 'spot_diameter_fullres' factor is different from the `spot` in Seurat object and thus users still need to get the value from the original json file.
scalefactors <- jsonlite::fromJSON(txt = file.path("./tutorial/spatial_imaging_data_visium_psoriasisSkin/scalefactors_json.json"))
spot.size <- 65 # the theoretical spot size (um) in 10X Visium
conversion.factor <- spot.size/scalefactors$spot_diameter_fullres
spatial.factors <- list(ratio = conversion.factor, tol = spot.size/2)
USERS can create a new Spatial CellChat object from a data
matrix or Seurat. If input is a Seurat object, the meta data in
the object will be used by default and USER must provide
group.by to define the cell groups. e.g, group.by = “ident”
for the default cell identities in Seurat object.
chat <- createSpatialCellChat(
object = seu, # Seurat
group.by = "final.clusters",
assay = "Spatial", # normalized
datatype = "spatial",
coordinates = spatial.locs,
spatial.factors = spatial.factors
)
#> ℹ Create a SpatialCellChat object from a Seurat object.
#> The `meta.data` slot in the Seurat object is used as cell meta information
#> Create a SpatialCellChat object from spatial imaging data...
#> Set cell identities for the new SpatialCellChat object
#> The cell groups used for SpatialCellChat analysis are FIB ENDO SM EG Keratinocyte Immune
chat
#> An object of class SpatialCellChat created from a single dataset
#> 33538 genes.
#> 905 cells.
#> SpatialCellChat analysis of spatial data! The input spatial locations are
#> x_cent y_cent
#> AAACCGGGTAGGTACC-1 3296 11251
#> AAACCGTTCGTCCAGG-1 5142 13546
#> AAACCTCATGAAGTTG-1 2110 10103
#> AAACGAGACGGTTGAT-1 10023 9648
#> AAACTTGCAAACGTAT-1 2109 11939
#> AAAGACTGGGCGCTTT-1 1583 8267
# check distance
# spatialCCCDistPlot(chat)
Before users employ Spatial CellChat to infer cell-cell communication, they need to set the ligand-receptor interaction database and identify over-expressed ligands or receptors.
Our database CellChatDB is a manually curated database of literature-supported ligand-receptor interactions in both human and mouse. CellChatDB v2 contains ~3,200 validated molecular interactions, including ~40% of secrete autocrine/paracrine signaling interactions, ~17% of cell-cell contact interactions, ~13% of extracellular matrix (ECM)-receptor interactions and ~30% non-protein signaling. Compared to CellChatDB v1, CellChatDB v2 adds more than 1000 protein and non-protein interactions such as metabolic and synaptic signaling.
CellChatDB v2 also adds additional functional annotations of ligand-receptor pairs, such as UniProtKB keywords (including biological process, molecular function, functional class, disease, etc), subcellular location and relevance to neurotransmitter.
Users can update CellChatDB by adding their own curated ligand-receptor pairs. Please check the tutorial on updating the ligand-receptor interaction database CellChatDB.
When analyzing human samples, use the database
CellChatDB.human; when analyzing mouse
samples, use the database
CellChatDB.mouse. CellChatDB categorizes
ligand-receptor pairs into different types, including “Secreted
Signaling”, “ECM-Receptor”, “Cell-Cell Contact” and “Non-protein
Signaling”. By default, the “Non-protein Signaling” are not used.
CellChatDB <- CellChatDB.human # use CellChatDB.mouse if running on mouse data
# showDatabaseCategory(CellChatDB)
# Show the structure of the database
dplyr::glimpse(CellChatDB$interaction)
#> Rows: 3,234
#> Columns: 28
#> $ interaction_name <chr> "TGFB1_TGFBR1_TGFBR2", "TGFB2_TGFBR1_TGFBR2",…
#> $ pathway_name <chr> "TGFb", "TGFb", "TGFb", "TGFb", "TGFb", "TGFb…
#> $ ligand <chr> "TGFB1", "TGFB2", "TGFB3", "TGFB1", "TGFB1", …
#> $ receptor <chr> "TGFbR1_R2", "TGFbR1_R2", "TGFbR1_R2", "ACVR1…
#> $ agonist <chr> "TGFb agonist", "TGFb agonist", "TGFb agonist…
#> $ antagonist <chr> "TGFb antagonist", "TGFb antagonist", "TGFb a…
#> $ co_A_receptor <chr> "", "", "", "", "", "", "", "", "", "", "", "…
#> $ co_I_receptor <chr> "TGFb inhibition receptor", "TGFb inhibition …
#> $ evidence <chr> "KEGG: hsa04350", "KEGG: hsa04350", "KEGG: hs…
#> $ annotation <chr> "Secreted Signaling", "Secreted Signaling", "…
#> $ interaction_name_2 <chr> "TGFB1 - (TGFBR1+TGFBR2)", "TGFB2 - (TGFBR1+T…
#> $ is_neurotransmitter <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FAL…
#> $ ligand.symbol <chr> "TGFB1", "TGFB2", "TGFB3", "TGFB1", "TGFB1", …
#> $ ligand.family <chr> "TGF-beta", "TGF-beta", "TGF-beta", "TGF-beta…
#> $ ligand.location <chr> "Extracellular matrix, Secreted, Extracellula…
#> $ ligand.keyword <chr> "Disease variant, Signal, Reference proteome,…
#> $ ligand.secreted_type <chr> "growth factor", "growth factor", "cytokine;g…
#> $ ligand.transmembrane <lgl> FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALS…
#> $ receptor.symbol <chr> "TGFBR2, TGFBR1", "TGFBR2, TGFBR1", "TGFBR2, …
#> $ receptor.family <chr> "Protein kinase superfamily, TKL Ser/Thr prot…
#> $ receptor.location <chr> "Cell membrane, Secreted, Membrane raft, Cell…
#> $ receptor.keyword <chr> "Membrane, Secreted, Disulfide bond, Kinase, …
#> $ receptor.surfaceome_main <chr> "Receptors", "Receptors", "Receptors", "Recep…
#> $ receptor.surfaceome_sub <chr> "Act.TGFB;Kinase", "Act.TGFB;Kinase", "Act.TG…
#> $ receptor.adhesome <chr> "", "", "", "", "", "", "", "", "", "", "", "…
#> $ receptor.secreted_type <chr> "", "", "", "", "", "", "", "", "", "", "", "…
#> $ receptor.transmembrane <lgl> TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRU…
#> $ version <chr> "CellChatDB v1", "CellChatDB v1", "CellChatDB…
# use a subset of CellChatDB for cell-cell communication analysis
CellChatDB.use <- subsetDB(CellChatDB, search = c("Secreted Signaling", "ECM-Receptor", "Cell-Cell Contact"), non_protein = F)
# Only uses the Secreted Signaling from CellChatDB v1
# CellChatDB.use <- subsetDB(CellChatDB, search = list(c("Secreted Signaling"), c("CellChatDB v1")), key = c("annotation", "version"))
# use all CellChatDB except for "Non-protein Signaling" for cell-cell communication analysis
# CellChatDB.use <- subsetDB(CellChatDB)
# use all CellChatDB for cell-cell communication analysis
# CellChatDB.use <- CellChatDB # simply use the default CellChatDB. We do not suggest to use it in this way because CellChatDB v2 includes "Non-protein Signaling" (i.e., metabolic and synaptic signaling) that can be only estimated from gene expression data.
# set the used database in the object
chat@DB <- CellChatDB.use
To infer spatially variable communications, Spatial CellChat identifies spatially variable ligands or receptors and then identifies spatially variable ligand-receptor interactions if either ligand or receptor are spatially variable.
# subset the expression data of signaling genes for saving computation cost
chat <- subsetData(chat) # This step is necessary even if using the whole database
chat <- preProcessing(chat)
#> ℹ Pre-processing from a SpatialCellChat object.
#> ✔ Pre-processing is done.
chat <- identifyOverExpressedGenes(
chat,
selection.method = "meringue", # method for selecting (spatially) variable features
do.grid = F # if true, do "grid" operation to speed up computation
)
#> >>> Choose spatially variable features using 'MERINGUE' method...
#> >>> The number of highly variable features is 864
chat <- identifyOverExpressedInteractions(
chat,
variable.both = F # only require that either ligand or receptor from one pair is over-expressed
)
#> ℹ Future strategy in use: `parallel with 2 workers`
#> >>> The number of highly variable ligand-receptor pairs used for signaling inference is 2114
Spatial CellChat infers the biologically significant cell-cell communication by assigning each interaction with a probability value and performing a permutation test. Spatial CellChat models the probability of cell-cell communication by integrating gene expression with prior known knowledge of the interactions between signaling ligands, receptors and their cofactors using the law of mass action, while also taking into account the spatial distance between cells or spots.
Users may need to adjust the parameter scale.distance
when working on data from other spatial transcriptomics technologies.
Please check the documentation in detail via
?computeCommunProb.
When inferring contact-dependent or juxtacrine signaling, users
should provide a value of contact.range and set
contact.dependent = TRUE. By default,
contact.range = 10, which is a typical human cell size.
chat <- computeCommunProb(
chat,
distance.use = TRUE, scale.distance = 0.2,
contact.dependent = TRUE,
interaction.range = 250, contact.range = 10
)
#> >>> Analyzing spatial transcriptomic data and preferring to infer interactions between individual cells...
#> >>> Apply a predefined spatial distance threshold based on the interaction length(=250um)...
#> >>> Contact range is set as 10um, to restrict the contact-dependent signaling.
#> >>> Run CellChat on spatial transcriptomic data using distances as constraints <<< [2026-02-16 12:14:04.160866]
#> >>> The input L-R pairs have both secreted signaling and contact-dependent signaling. Run CellChat in a contact-dependent manner for `Cell-Cell Contact` signaling, and in a diffusion manner based on the `interaction.range` for other L-R pairs.
#> ℹ Future strategy in use: `parallel with 2 workers`
#> >>> The number of cells and L-R pairs in Dim(Prob.cell): 905 905 2114
#> ✔ CellChat inference is done. Parameter values are stored in `object@options$parameter` <<< [2026-02-16 12:18:29.011013]
Users can filter out statistically non-significant communications as well as communications mediated by ligand–receptor pairs with only few interactions.
chat <- filterProbability(chat)
#> >>> Filter out non-significant communication with a probability quantile being 0.95 for each L-R pair...
#> ℹ Future strategy in use: `parallel with 2 workers`
#> ✔ Filtering is done.
chat <- filterCommunication(
chat, min.cells = NULL,
min.links = 10,
min.cells.sr = 10
)
#> >>> Filter communication according to min.links...
#> The cell-cell communication related with # 107 L-R pairs are excluded due to the few number of interactions.
#> >>> Filter communication according to min.cell.sr...
#> The cell-cell communication related with # 116 L-R pairs are excluded due to the few number of sending/receiving cells.
#> ✔Filtering cell-cell communication is done.<<< [2026-02-16 12:22:34.234732]
# # checkpoint (optional)
# readr::write_rds(chat,file = "./results/chat_computeCommunProb.rds")
# chat <- readr::read_rds(file = "./results/chat_computeCommunProb.rds")
For low-resolution spatial data, such as the dataset used in this
example, use computeAvgCommunProb_Visium to compute
group-level cell–cell communication and pass the cell type proportions
(if available) through parameter cell.type.decomposition.
For high-resolution data, please use computeAvgCommunProb
instead.
To quickly examine the inference results, USER can set
nboot = 20 in computeAvgCommunProb.
chat <- computeAvgCommunProb_Visium(
chat,
cell.type.decomposition = as.matrix(cell.type.decomposition),
avg.type = 'avg',
nboot = 100,
do.permutation = T
)
#> >>> The cell groups used for averaging cell-cell communication are FIB ENDO SM EG Keratinocyte Immune
#> >>> Compute group-level cell-cell communication... <<< [2026-02-16 12:22:34.449614]
#> >>> compute the average signaling per cell group...
#> ℹ Future strategy in use: `parallel with 2 workers`
#> >>> Perform permutation test for group-level communication... <<< [2026-02-16 12:24:55.271369]
#> ℹ Future strategy in use: `parallel with 2 workers`
#> ✔Inference of group-level cell-cell communication is done. Parameter values are stored in `object@options$parameter` <<< [2026-02-16 12:27:41.310724]
Users can filter out the cell group-level communication if there are only few cells in certain cell groups. By default, the minimum number of cells required in each cell group for cell-cell communication is 10.
chat <- filterCommunication(chat, min.cells = 10, min.links = NULL, min.cells.sr = NULL)
# # checkpoint (optional)
# readr::write_rds(chat,file = "./results/Chat_computeAvgCommunProb.rds")
# chat <- readr::read_rds(file = "./results/Chat_computeAvgCommunProb.rds")
We provide a function subsetCommunication to easily
access the inferred cell-cell communications of interest. For
example,
df.net <- subsetCommunication(chat) returns a
data frame consisting of all the inferred cell-cell communications at
the level of ligands/receptors. Set slot.name = "netP" to
access the the inferred communications at the level of signaling
pathways
df.net <- subsetCommunication(chat, sources.use = c(1,2), targets.use = c(4,5))
gives the inferred cell-cell communications sending from cell groups 1
and 2 to cell groups 4 and 5.
df.net <- subsetCommunication(chat, signaling = c("WNT", "TGFb"))
gives the inferred cell-cell communications mediated by signaling WNT
and TGFb.
df.net <- subsetCommunication(chat)
head(df.net)
#> source target ligand receptor prob pval
#> 1 SM EG TGFB1 TGFbR1_R2 1.913768e-04 0.00
#> 2 EG Keratinocyte TGFB1 TGFbR1_R2 1.532117e-04 0.04
#> 3 Keratinocyte Keratinocyte TGFB1 TGFbR1_R2 2.174207e-04 0.00
#> 4 ENDO EG TGFB2 TGFbR1_R2 5.160736e-05 0.00
#> 5 EG EG TGFB2 TGFbR1_R2 9.464101e-05 0.00
#> 6 EG Keratinocyte TGFB2 TGFbR1_R2 9.985258e-05 0.00
#> interaction_name interaction_name_2 pathway_name annotation
#> 1 TGFB1_TGFBR1_TGFBR2 TGFB1 - (TGFBR1+TGFBR2) TGFb Secreted Signaling
#> 2 TGFB1_TGFBR1_TGFBR2 TGFB1 - (TGFBR1+TGFBR2) TGFb Secreted Signaling
#> 3 TGFB1_TGFBR1_TGFBR2 TGFB1 - (TGFBR1+TGFBR2) TGFb Secreted Signaling
#> 4 TGFB2_TGFBR1_TGFBR2 TGFB2 - (TGFBR1+TGFBR2) TGFb Secreted Signaling
#> 5 TGFB2_TGFBR1_TGFBR2 TGFB2 - (TGFBR1+TGFBR2) TGFb Secreted Signaling
#> 6 TGFB2_TGFBR1_TGFBR2 TGFB2 - (TGFBR1+TGFBR2) TGFb Secreted Signaling
#> evidence
#> 1 KEGG: hsa04350
#> 2 KEGG: hsa04350
#> 3 KEGG: hsa04350
#> 4 KEGG: hsa04350
#> 5 KEGG: hsa04350
#> 6 KEGG: hsa04350
CellChat computes the communication probability on signaling pathway level by summarizing the communication probabilities of all ligands-receptors interactions associated with each signaling pathway.
NB: The inferred intercellular communication network of each ligand-receptor pair and each signaling pathway is stored in the slot ‘net’ and ‘netP’, respectively.
chat <- computeCommunProbPathway(chat)
#> >>> Compute the communication probability between cell groups at signaling pathway level by summarizing all related ligands/receptors...
#> >>> Compute the communication probability between individual cells at signaling pathway level by summarizing all related ligands/receptors...
#> >>> Subset the pathways with non-zero communication probability and arrange them in a decreasing order based on the total communication probabilities ...
#> >>> The number of cells and pathways in Dim(prob.cell.pathways) are : 905 905 187
#> ✔ Computing the communication probability on signaling pathway level is done.
We can calculate the aggregated cell-cell communication network by
counting the number of links or summarizing the communication
probability. USER can also calculate the aggregated network among a
subset of cell groups by setting sources.use and
targets.use.
chat <- aggregateNet(chat)
# # checkpoint (optional)
# readr::write_rds(chat,file = "./results/Chat_computeCommunProbPathway.rds")
# chat <- readr::read_rds(file = "./results/Chat_computeCommunProbPathway.rds")
Users can run netAnalysis_computeCentrality with
degree.only = T to speed up computation when only
“outdeg_unweighted”, “indeg_unweighted”,“outdeg” and “indeg” are needed
to do analysis.
chat <- netAnalysis_computeCentrality(
chat,
slot.name = "net",
do.group = F,
degree.only = T
)
#> ℹ Future strategy in use: `parallel with 2 workers`
#> ✔ Computing Net Centrality is done.
chat <- netAnalysis_computeCentrality(
chat,
slot.name = "net",
do.group = T,
degree.only = T
)
#> ℹ Future strategy in use: `parallel with 2 workers`
#> ✔ Computing Net Centrality is done.
chat <- netAnalysis_computeCentrality(
chat,
slot.name = "netP",
do.group = F,
degree.only = T
)
#> ℹ Future strategy in use: `parallel with 2 workers`
#> ✔ Computing Net Centrality is done.
chat <- netAnalysis_computeCentrality(
chat,
slot.name = "netP",
do.group = T,
degree.only = T
)
#> ℹ Future strategy in use: `parallel with 2 workers`
#> ✔ Computing Net Centrality is done.
# # checkpoint (optional)
# readr::write_rds(chat,file = "./results/Chat_computeCentrality.rds")
# chat <- readr::read_rds(file = "./results/Chat_computeCentrality.rds")
Upon infering the cell-cell communication network, Spatial CellChat provides various functionality for further data exploration, analysis, and visualization.
# show the cell type proportion of each spot
spatialDimPlot(chat, proportion = cell.type.decomposition, point.size = 1.5)
We provide the function spatialFeaturePlot to display
gene expression distributions, including the expression patterns of
genes associated with specific pathways or L-R pairs.
Here we take input of one signaling pathway as an example. All the
signaling pathways showing significant communications can be accessed by
chat@netP$pathways.
pathway.show <- "TNF"
# show the expression distributions of genes associated with the specific pathway
spatialFeaturePlot(chat, signaling = pathway.show, do.group = FALSE, do.binary = FALSE, color.heatmap = "Spectral", point.size = 1.3)
The function extractEnrichedLR is used to extract all
the significant interactions (L-R pairs) and related signaling genes for
a given signaling pathway. Users can set do.binary = TRUE
in spatialFeaturePlot to binarize and visualize the
expression distribution of the ligand and receptor genes in a specific
LR pair within the same plot. In this case, parameter
cutoff must be provided as the threshold for expression
levels.
# show the expression distributions of genes associated with the specific L-R pair
enrichedLR <- extractEnrichedLR(chat, signaling = pathway.show, do.group = FALSE)
LR.show <- enrichedLR[1,,drop = FALSE] # only show one ligand-receptor pair
spatialFeaturePlot(chat, pairLR.use = LR.show, do.group = FALSE, do.binary = TRUE, cutoff = 0.05, point.size = 1.5)
gg1 <- spatialVisual_scoring(chat, signaling = pathway.show, slot.name = "netP", do.group = FALSE, measure = c("outdeg"), do.binary = FALSE, color.heatmap = "Blues", point.size = 1)
gg2 <- spatialVisual_scoring(chat, signaling = pathway.show, slot.name = "netP", do.group = FALSE, measure = c("indeg"), do.binary = FALSE, color.heatmap = "Reds", point.size = 1)
patchwork::wrap_plots(gg1, gg2, ncol =2)
Setting merge = TRUE allows the simultaneous display of
outgoing and incoming scores, as well as their overlapping regions.
spatialVisual_scoring(chat, signaling = pathway.show, do.group = FALSE, merge = TRUE, do.binary = FALSE, point.size = 1)
Here we take input of one L-R pairs as an example. All the L-R pairs
showing significant communications can be accessed by
chat@net$LR.sig.
LR.show <- chat@net$LR.sig[1]
gg1 <- spatialVisual_scoring(chat, signaling = LR.show, slot.name = "net", do.group = FALSE, measure = c("outdeg"), do.binary = FALSE, color.heatmap = "Blues", point.size = 1)
gg2 <- spatialVisual_scoring(chat, signaling = LR.show, slot.name = "net", do.group = FALSE, measure = c("indeg"), do.binary = FALSE, color.heatmap = "Reds", point.size = 1)
patchwork::wrap_plots(gg1, gg2, ncol =2)
Visualization of cell-cell communication at different
levels: One can visualize the inferred communication network of
signaling pathways using netVisual_aggregate, and visualize
the inferred communication networks of individual L-R pairs associated
with that signaling pathway using netVisual_individual.
We provide four different visualization methods: circle plot,
hierarchy plot, chord diagram, and spatial plot. Users can select their
preferred method through the layout parameter. Please check
the Full
tutorial for CellChat analysis of a single dataset with detailed
explanation of each function for detailed explanations. Here we only
showcase the circle plot.
netVisual_aggregate(chat, signaling = pathway.show, layout = "circle")
Spatial CellChat used out-degree and in-degree in weighted-directed networks to respectively identify dominant senders and receivers for the intercellular communications.
library(ComplexHeatmap)
library(RColorBrewer)
netAnalysis_signalingRole_network(
chat, signaling = pathway.show, slot.name = "netP",
measure = c("outdeg","indeg"), measure.name = c("Sender","Receiver"),
width = 8, height = 3, font.size = 10
)
netVisual_heatmap(chat, slot.name="netP", signaling = pathway.show, color.heatmap = "Reds")
idx.Paracrine <- which(chat@LR$LRsig$annotation=="Secreted Signaling")
idx.Juxtracrine <- which(chat@LR$LRsig$annotation=="Cell-Cell Contact")
# incoming scores
g1 <- spatialGiPlot(chat,return.object = F,plot.title = "Incoming hotspot scores of secreted signaling",slot.name = "net",signaling.name = idx.Paracrine,measure = c("indeg"),measure.name = c("incoming"),point.size = 1)
g2 <- spatialGiPlot(chat,return.object = F,plot.title = "Incoming hotspot scores of cell-cell contact signaling",slot.name = "net",signaling.name = idx.Juxtracrine,measure = c("indeg"),measure.name = c("incoming"),point.size = 1)
patchwork::wrap_plots(g1, g2, ncol = 2)
chat <- spatialGiPlot(chat,plot.title = "Secreted Signaling",slot.name = "net",signaling.name = idx.Paracrine,measure = c("indeg"),measure.name = c("incoming"),show.plot = FALSE)
chat <- spatialGiPlot(chat,plot.title = "Cell-Cell Contact",slot.name = "net",signaling.name = idx.Juxtracrine,measure = c("indeg"),measure.name = c("incoming"),show.plot = FALSE)
chat@meta <- chat@meta %>%
mutate(SecretedHotspot = Getis.Ord.Gi.Secreted.Signaling*(Getis.Ord.Gi.P.Secreted.Signaling<0.05)) %>%
mutate(SecretedHotspot = ifelse(SecretedHotspot > 0, "Hot", ifelse(SecretedHotspot < 0, "Cold", "Other")))
spatialDimPlot(chat,group.by = "SecretedHotspot",point.size = 1.5, color.use = c("Cold"="#2171b5", "Hot"="#cb181d", "Other"="#E5E5E5"))
spatialLeePlot(chat,group.by2 = "SecretedHotspot",cutoff.Lee = 0.05, y.levels = c("Hot","Cold","Other"))
#> [1] "lw.type = Itself"
We provide the function rankNet for ranking
communication-active signaling. When analyzing signaling pathways, set
slot.name = 'netP'; when analyzing ligand–receptor pairs,
set slot.name = 'net'.
In addition, users can specify the type of signaling using the
signaling.type parameter, which defaults to
NULL for the overall ranking. And the source and target
cell groups can be defined using parameters sources.use and
targets.use, respectively.
g1 <- rankNet(chat, mode = "single", slot.name = "netP", measure = "weight", signaling.type = "Secreted Signaling",title = "Secreted Signaling")
g2 <- rankNet(chat, mode = "single", slot.name = "netP", measure = "weight", signaling.type = "ECM-Receptor",title = "ECM-Receptor")
g3 <- rankNet(chat, mode = "single", slot.name = "netP", measure = "weight", signaling.type = "Cell-Cell Contact",title = "Cell-Cell Contact")
patchwork::wrap_plots(g1, g2, g3, ncol = 3)
If there are too many signaling pathways, users can store the results as a data frame for further analysis.
df1 <- with(g1$data, g1$data[order(-contribution),]); df1$type <- "Secreted Signaling"
df2 <- with(g2$data, g2$data[order(-contribution),]); df2$type <- "ECM-Receptor"
df3 <- with(g3$data, g3$data[order(-contribution),]); df3$type <- "Cell-Cell Contact"
df <- rbind(df1,df2,df3)
head(df)
#> name contribution contribution.scaled group type
#> SEMA3 SEMA3 0.10508789 0.4438609 pathways Secreted Signaling
#> ncWNT ncWNT 0.07955609 0.3950550 pathways Secreted Signaling
#> CCL CCL 0.06732568 0.3706156 pathways Secreted Signaling
#> MHC-I MHC-I 0.05761556 0.3503900 pathways Secreted Signaling
#> MK MK 0.05546453 0.3457801 pathways Secreted Signaling
#> EGF EGF 0.05005547 0.3339318 pathways Secreted Signaling
The function netAnalysis_contribution is provided to
rank the contribution of each L-R pair within a specified signaling
pathway.
netAnalysis_contribution(chat, signaling = 'ncWNT')
We use the Lee statistic to infer the spatial co-occurrence between
two features. Users can specify the type of distance weight matrix via
the lw.type parameter in function
spatialLeePlot and the distance weight matrix will then be
computed automatically. Alternatively, a precomputed distance weight
matrix can be provided directly through the lw
parameter.
Genes <- extractEnrichedLR(chat, signaling = "CXCL", do.group = FALSE, geneLR.return = TRUE)$geneLR
mat1 <- t(as.matrix(chat@data[Genes,]))
indeg <- chat@net$centr.cell['indeg',,]
LR.pairs <- extractEnrichedLR(chat, signaling = "IL17", do.group = FALSE)$interaction_name
mat2 <- indeg[,LR.pairs]
spatialLeePlot(chat, group.by2 = mat2, group.by1 = mat1, lw.type = "interaction.range")
#> [1] "lw.type = interaction.range"
# choose the rank K first
# chat <- identifyCellTopics(chat,slot.name = "net",pattern = "incoming", nmf.k = seq(8,20,4))
# then perform cell topic analysis
topic.k = 12
chat <- identifyCellTopics(chat,slot.name = "net",pattern = "incoming",topic.k = topic.k, verbose=FALSE)
The spatial distribution of each topic.
spatialTopicPlot(
chat,
pattern = "incoming",
color.heatmap = "Reds",
show.legend = FALSE,
point.size = 1.3,
ncol = topic.k/2
)
The cell type composition of each topic.
netVisual_TopicComposition(
chat,
x.group = NULL, # use cell type annotations
y.group = "topicIn",
cluster.rows = TRUE
)
The ranking of enriched ligand-receptor pairs within cell topics. Note that only the top signaling pathways are showed with a text annotation.
netVisual_TopicSignaling(
chat,
pattern = "incoming",
ncol = topic.k/2
)
# Save the Spatial CellChat object
readr::write_rds(chat,file = "./results/chat_Downstream.rds")